package no.sachmuld.methodcombination.api.reflection;

import no.sachmuld.methodcombination.api.BehaviourChain;
import no.sachmuld.methodcombination.api.CrosscuttingBehaviour;
import no.sachmuld.methodcombination.api.Direction;
import no.sachmuld.methodcombination.api.reflection.component.*;

import java.lang.reflect.Method;

/**
 *
 */
public class Crosscutting<R> extends DelegatingMethodCombination<CrosscuttingBehaviour, R> {

    @Override
    public Crosscutting<R> build(final Class behaviourClass, final Method targetMethod) {

        final Direction direction = Direction.BOTTOM_UP;

        final CrosscuttingAroundMethodCombination<CrosscuttingBehaviour, R> around = new CrosscuttingAroundMethodCombination<>();
        final CrosscuttingBeforeMethodCombination<CrosscuttingBehaviour>    before = new CrosscuttingBeforeMethodCombination<>();
        final PrimaryMethodCombination<CrosscuttingBehaviour, R>            primary = new PrimaryMethodCombination<>(direction);
        final CrosscuttingAfterMethodCombination        after = new CrosscuttingAfterMethodCombination();

        buildChildren(behaviourClass, targetMethod, around, before, primary, after);

        executedBy(
                around.inner(
                        new AbstractMethodCombination<CrosscuttingBehaviour, R>() {

                            @Override
                            public R execute(final Object targetObject, BehaviourChain<? extends CrosscuttingBehaviour> behaviourChain, Object... parameters) {

                                before.execute(targetObject, behaviourChain, parameters);

                                R result = primary.execute(targetObject, behaviourChain, parameters);

                                after.execute(targetObject, behaviourChain, parameters);

                                return result;
                            }
                        }));

        return this;

    }

}
